/*
 * triangle.cpp
 *
 *      Author: Jerome RD Soine and Christoph A Brand
 *      Institution: Schwarz goup, Institute for Theoretical Physics, Heidelberg University, Germany
 */

#include "../../../../../../include/base/cell_models/ACM/geometry/base/triangle.h"
#include "../../../../../../include/base/cell_models/ACM/geometry/base/vertex.h"
#include "../../../../../../include/base/cell_models/ACM/geometry/base/edge.h"
#include <list>
#include <iostream>
#include <cmath>
#include <string>
#include <sstream>

using namespace std;

string Triangle::toString() {
	ostringstream os;
	os << "T [ " << tips[0]->toString() << " , " << tips[1]->toString()
			<< " , " << tips[2]->toString() << " ]";
	return os.str();
}

Triangle::Triangle(Vertex* v1, Vertex* v2, Vertex* v3, Edge* e1, Edge* e2,
		Edge* e3) {
	tips.reserve(3);
	tips.push_back(v1);
	tips.push_back(v2);
	tips.push_back(v3);

	edges.reserve(3);
	edges.push_back(e1);
	edges.push_back(e2);
	edges.push_back(e3);

	v1->getTrianglesContainingVertex()->push_back(this);
	v2->getTrianglesContainingVertex()->push_back(this);
	v3->getTrianglesContainingVertex()->push_back(this);

	e1->getAdjacentTriangles()->push_back(this);
	e2->getAdjacentTriangles()->push_back(this);
	e3->getAdjacentTriangles()->push_back(this);

	getThirdTip(e1)->getEdgesOppositeToVertex()->push_back(e1);
	getThirdTip(e2)->getEdgesOppositeToVertex()->push_back(e2);
	getThirdTip(e3)->getEdgesOppositeToVertex()->push_back(e3);
}

Vertex Triangle::normalizedNormal(){
	Vertex n = normal();
	return n/n.abs();
}

Vertex Triangle::normal(){
	Vertex v1 = *tips[1] - *tips[0];
	Vertex v2 = *tips[2] - *tips[1];
	Vertex ret = v1.cross(v2);
	return ret;
}


Vertex * Triangle::getThirdTip(Edge * e){
	Vertex * tip1 = e->getHead();
	Vertex * tip2 = e->getTail();

	if(tips[0] != tip1 && tips[0] != tip2) return tips[0];
	else if(tips[1] != tip1 && tips[1] != tip2) return tips[1];
	else if(tips[2] != tip1 && tips[2] != tip2) return tips[2];
	else return NULL;
}

Edge * Triangle::getEdgeNotConnectedToTip(Vertex & v){
	Vertex * tip = &v;
	if(tip != tips[0] && tip != tips[1] && tip != tips[2]) return NULL; //v is not a tip of this triangle
	for(unsigned int i=0; i<3; i++){
		Edge * e = edges[i];
		if(!e->containsVertex(tip)) return e;
	}
	return NULL; //ERROR
}

Vertex Triangle::constructEdgeNotConnectedToTipWithOrientation(Vertex & v){
	Vertex * tip = &v;
	if(tip != tips[0] && tip != tips[1] && tip != tips[2]) return Vertex(0,0,0); //v is not a tip of this triangle

	for(unsigned int i=0; i<3; i++){
		if(tips[i] == tip){
			return *tips[(i+2)%3]-*tips[(i+1)%3];
		}
	}
	return Vertex(0,0,0); //ERROR
}


double Triangle::area(){
	return normal().abs() * 0.5;
}

double Triangle::volumeContribution(){
	Vertex C = *tips[1];
	return normal()*C/6;
}

bool Triangle::hasTip(Vertex * v){
	return v==tips[0] || v == tips[1] || v == tips[2];
}
